/*
 * ServerCommunicator.cpp
 *
 *  Created on: 24/05/2014
 *      Author: javier
 */

#include "ServerMessageSender.h"
#include "BZPController.h"
#include "Utils.h"
#include "ProtocoloCliente.h"
#include <iostream>

ServerMessageSender::ServerMessageSender(BZPController* controller,
		ClientSocket& socket) :
		socket(socket) {
	this->controller = controller;
	conected = false;
	idJugador = -1;
	idPartida = -1;
}

void ServerMessageSender::run() {
	while (isRunning()) {
		try {
			Message message = messagesQueue.pop2();
			Message m;
			m.id = idJugador;
			std::string mStr;
//			std::cout << "Enviando al server: " << message.toString()
//					<< std::endl;
			if (message.code == NEW_GAME) {
				m.code = NEW_GAME;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
			} else if (message.code == BM_MOVE_UP) {
				m.code = BM_MOVE_UP;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
			} else if (message.code == BM_MOVE_DOWN) {
				m.code = BM_MOVE_DOWN;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
			} else if (message.code == BM_MOVE_LEFT) {
				m.code = BM_MOVE_LEFT;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
			} else if (message.code == BM_MOVE_RIGHT) {
				m.code = BM_MOVE_RIGHT;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
			} else if (message.code == GET_CAMPAIGNS) {
				ProtocoloCliente::send_opcionSeleccionadaInicial(
						socket.getSockfd(), true);
				std::string campaigns =
						ProtocoloCliente::recv_campaniasExistentes(
								socket.getSockfd());
				controller->setCampaigns(campaigns);
				controller->showCampaigns();
			} else if (message.code == SELECT_CAMPAIGN) {
				ProtocoloCliente::send_campaniaSeleccionadaYnombrePartida(
						socket.getSockfd(), message.args[0], message.args[1]);
				controller->showWaitingPlayers();
				std::string campaigns =
						ProtocoloCliente::recv_partidaListaParaComenzar(
								socket.getSockfd());
				controller->decideStartGameView();
			} else if (message.code == JOIN_MATCH) {
				ProtocoloCliente::send_opcionSeleccionadaInicial(
						socket.getSockfd(), false);
				std::string partidas =
						ProtocoloCliente::recv_partidasExistentesNoComenzadas(
								socket.getSockfd());
				controller->setPartidas(partidas);
				controller->showPartidas();
			} else if (message.code == START_JOIN_MATCH) {
				ProtocoloCliente::send_partidaSeleccionada(socket.getSockfd(),
						message.args[0]);
				// Esperando que los demas jugadores se unan
				controller->showWaitingPlayers();
				std::string resp = ProtocoloCliente::recv_partidaIniciada(
						socket.getSockfd());
				std::vector<std::string> tokens = Utils::split(resp, '|');
				idPartida = Utils::stringToInt(tokens[0]);
				nombrePartida = tokens[1];
				if (idPartida < 0) {
					controller->showMainMenu();
					break;
				}
				// TODO borrar
//				std::string scenarioDimensions =
//						ProtocoloCliente::recv_dimensionEscenario(
//								socket.getSockfd());
				std::string repr = ProtocoloCliente::recv_scenario(
						socket.getSockfd());
				Scenario s;
				s.setScenarioRepr(repr);
				controller->loadScenario(s);
			} else if (message.code == START_MATCH) {
				if (message.flags[0] == true) {
					std::string mensajeAEnviar = "1|";
					mensajeAEnviar += message.args[0];
					ProtocoloCliente::send_comenzarPartida(socket.getSockfd(),
							message.flags[0], mensajeAEnviar);
					std::string resp = ProtocoloCliente::recv_partidaIniciada(
							socket.getSockfd());
					std::vector<std::string> tokens = Utils::split(resp, '|');
					idPartida = Utils::stringToInt(tokens[0]);
					if (tokens.size() > 1)
						nombrePartida = tokens[1];
					else
						nombrePartida = "(sin nombre)";
//					std::string scenarioDimensions =
//							ProtocoloCliente::recv_dimensionEscenario(
//									socket.getSockfd());
				} else {
					std::string mensajeAEnviar = "0";
					ProtocoloCliente::send_comenzarPartida(socket.getSockfd(),
							message.flags[0], mensajeAEnviar);
					controller->showMainMenu();
					break;
				}
				std::string repr = ProtocoloCliente::recv_scenario(
						socket.getSockfd());
				Scenario s;
				s.setScenarioRepr(repr);
				controller->loadScenario(s);
			} else if (message.code == DROP_BOMB) {
				m.code = DROP_BOMB;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
			} else if (message.code == LOAD_NEXT_SCENARIO) {
				m.code = LOAD_NEXT_SCENARIO;
				mStr = m.toString();
				ProtocoloCliente::send_update(socket.getSockfd(), mStr);
				std::string r = ProtocoloCliente::recv_scenario(
						socket.getSockfd());
				Scenario s;
				s.setScenarioRepr(r);
				controller->loadScenario(s);
			} else {
				std::cout << "Error: envio de mensaje desconocido: " << message.toString() << std::endl;
			}
		} catch (ComunicacionException& e) {
			std::cerr << "Error en comunicacion con servidor: " << e.error()<< std::endl;
			controller->showMainMenu();
		}
	}
}

void ServerMessageSender::sendNewGameMessage() {
	Message message;
	message.code = GET_CAMPAIGNS;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendResetGameMessage() {
	Message message;
	message.code = NEW_GAME;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendJoinGameMessage() {
	Message message;
	message.code = JOIN_MATCH;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendMovementUp() {
	Message message;
	message.code = BM_MOVE_UP;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendMovementDown() {
	Message message;
	message.code = BM_MOVE_DOWN;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendMovementRight() {
	Message message;
	message.code = BM_MOVE_RIGHT;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendMovementLeft() {
	Message message;
	message.code = BM_MOVE_LEFT;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

ServerMessageSender::~ServerMessageSender() {
	socket.shutdownConexion();
	socket.matarConexion();
}

void ServerMessageSender::sendSelectCampaign(std::string& idCampania,
		std::string& nombrePartida) {
	Message message;
	message.code = SELECT_CAMPAIGN;
	message.args.push_back(idCampania);
	message.args.push_back(nombrePartida);
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendStartMatch(bool comenzar, string & idPartida) {
	Message message;
	message.code = START_MATCH;
	message.flags.push_back(comenzar);
	message.args.push_back(idPartida);
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::sendDropBomb() {
	Message message;
	message.code = DROP_BOMB;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}

void ServerMessageSender::init() {
	try {
		socket.conectar();
		std::string resp = ProtocoloCliente::recv_updates(socket.getSockfd());
		if (resp.compare("OK") == 0) {
			conected = true;
		} else {
			conected = false;
		}
	} catch (ComunicacionException& e) {
		std::cout << "Sin conexion en sender" << std::endl;
	}
}

bool ServerMessageSender::isConnected() {
	return conected;
}

void ServerMessageSender::sendLoadNextScenario() {
	Message message;
	message.code = LOAD_NEXT_SCENARIO;
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();

}

void ServerMessageSender::setIdJugador(int idJugador) {
	this->idJugador = idJugador;
}

void ServerMessageSender::sendSelectedMatch(std::string& idPartida) {
	Message message;
	message.code = START_JOIN_MATCH;
	message.args.push_back(idPartida);
	mutex.lock();
	messagesQueue.push(message);
	mutex.unlock();
}
